package dao

import (
	"context"
	"mini-app/internal/dal"
	"mini-app/internal/define"
	"mini-app/internal/models"
	"strings"
	"time"

	"gorm.io/gorm"
)

type Order struct{}

func (Order) Create(
	ctx context.Context,
	query *dal.Query,
	openid,
	orderID,
	batchID,
	robotID string,
	orderStatus int,
	goodsID string,
	goodsType int,
	goodsName string,
	count int,
	univalent, amount, points, expressFee float64,
	purchaseMethod int,
	onlineEventID string, // 活动id
	userAddress models.UserAddress, // 用户id
) (outTradeNo string, err error) {
	o := query.Order
	d := models.Order{}
	d.ID = orderID
	d.Openid = openid
	d.BatchID = batchID
	d.RobotID = robotID
	d.OrderStatus = orderStatus
	d.GoodsID = goodsID
	d.GoodsType = goodsType
	d.GoodsName = goodsName
	d.Count = count
	d.Univalent = univalent
	d.Amount = amount
	d.Points = points
	d.ExpressFee = expressFee
	d.PurchaseMethod = purchaseMethod
	d.OnlineEventID = onlineEventID
	d.UserName = userAddress.UserName
	d.TelNumber = userAddress.TelNumber
	d.PostalCode = userAddress.PostalCode
	d.ProvinceName = userAddress.ProvinceName
	d.CityName = userAddress.CityName
	d.CountyName = userAddress.CountyName
	d.StreetName = userAddress.StreetName
	d.DetailAddress = userAddress.DetailAddress
	d.CreatedAt = time.Now().Unix()
	err = o.WithContext(ctx).Create(&d)
	return d.BatchID, err
}

func (Order) OrderList(ctx context.Context, query *dal.Query, openid, ID, batchID, robotID, goodsIDs string, orderStatus, page, limit int) (
	res []*models.Order, total int64, err error,
) {
	o := query.Order
	tx := o.WithContext(ctx)
	if openid != "" {
		tx = tx.Where(o.Openid.Eq(openid))
	}
	if ID != "" {
		tx = tx.Where(o.ID.Eq(ID))
	}
	if batchID != "" {
		tx = tx.Where(o.BatchID.Eq(batchID))
	}
	if robotID != "" {
		tx = tx.Where(o.RobotID.Eq(robotID))
	}
	if goodsIDs != "" {
		tx = tx.Where(o.GoodsID.In(strings.Split(goodsIDs, ",")...))
	}
	if orderStatus != 0 && orderStatus != define.OrderStatusClosed {
		if orderStatus == define.OrderStatusDone {
			tx = tx.Where(o.OrderStatus.In([]int{
				define.OrderStatusDone,          // 已完成
				define.OrderStatusPendingReview, // 待评测
				define.OrderStatusReviewed,      // 已评测
			}...))
		} else if orderStatus == define.OrderStatusApplied {
			tx = tx.Where(o.OnlineEventID.IsNotNull()) // 活动订单
		} else {
			tx = tx.Where(o.OrderStatus.Eq(orderStatus))
		}
	}
	// 超时15分钟的订单，判定为关闭，不显示到支付列表中
	if orderStatus == define.OrderStatusUnpaid {
		tx = tx.Where(
			o.WithContext(ctx).
				Where(
					o.WithContext(ctx).Where(o.OnlineEventID.IsNotNull()).Where(o.CreatedAt.Gte(time.Now().Unix() - 3600*24*7)),
				).
				Or(
					o.WithContext(ctx).Where(o.OnlineEventID.IsNull()).Where(o.CreatedAt.Gte(time.Now().Unix() - 15*60)),
				),
		)
	}
	// 关闭的订单
	// 未支付的超时订单
	if orderStatus == define.OrderStatusClosed {
		tx = tx.Where(o.OrderStatus.Eq(define.OrderStatusUnpaid))
		tx = tx.Where(
			o.WithContext(ctx).
				Where(
					o.WithContext(ctx).Where(o.OnlineEventID.IsNotNull()).Where(o.CreatedAt.Lt(time.Now().Unix() - 3600*24*7)),
				).
				Or(
					o.WithContext(ctx).Where(o.OnlineEventID.IsNull()).Where(o.CreatedAt.Lt(time.Now().Unix() - 15*60)),
				),
		)
	}
	// 按主订单进行分页
	// total 为主订单的总数
	var batchIDs []string
	total, _ = tx.Group(o.BatchID).Count()
	tx.Order(o.CreatedAt.Desc(), o.ID.Desc()).Group(o.BatchID).Offset(GetPageOffset(page, limit)).Limit(GetPageLimit(limit)).Pluck(o.BatchID, &batchIDs)

	// 返回每页主订单包含的子单
	tx1 := o.WithContext(ctx)
	res, _ = tx1.Where(o.BatchID.In(batchIDs...)).
		Order(o.CreatedAt.Desc(), o.ID.Desc()).
		Find()
	return
}

func (Order) Detail(ctx context.Context, query *dal.Query, openid, ID, batchID, robotID, goodsIDs string, orderStatus int) (
	res *models.Order, err error,
) {
	o := query.Order
	tx := o.WithContext(ctx)
	if openid != "" {
		tx = tx.Where(o.Openid.Eq(openid))
	}
	if ID != "" {
		tx = tx.Where(o.ID.Eq(ID))
	}
	if batchID != "" {
		tx = tx.Where(o.BatchID.Eq(batchID))
	}
	if robotID != "" {
		tx = tx.Where(o.RobotID.Eq(robotID))
	}
	if goodsIDs != "" {
		tx = tx.Where(o.GoodsID.In(strings.Split(goodsIDs, ",")...))
	}
	if orderStatus != 0 {
		tx = tx.Where(o.OrderStatus.Eq(orderStatus))
	}
	res, err = tx.Select(o.ALL, o.Amount.Sum().As("total_amount")).Take()
	return
}

func (Order) OrderStatusChange(ctx context.Context, query *dal.Query, ID, batchID string, orderStatus int) (err error) {
	if ID == "" && batchID == "" {
		return
	}
	if orderStatus <= 0 {
		return
	}
	tx := query.Order.WithContext(ctx)
	if ID != "" {
		tx = tx.Where(query.Order.ID.Eq(ID))
	}
	if batchID != "" {
		tx = tx.Where(query.Order.BatchID.Eq(batchID))
	}
	tx.UpdateColumn(query.Order.OrderStatus, orderStatus)
	return
}

func (Order) OrderPointsChange(ctx context.Context, query *dal.Query, ID, batchID string, points float64) (err error) {
	if ID == "" && batchID == "" {
		return
	}
	if points <= 0 {
		return
	}
	tx := query.Order.WithContext(ctx)
	if ID != "" {
		tx = tx.Where(query.Order.ID.Eq(ID))
	}
	if batchID != "" {
		tx = tx.Where(query.Order.BatchID.Eq(batchID))
	}
	tx.UpdateColumn(query.Order.Points, points)
	return
}

func (Order) FreeExpressFeeList(
	ctx context.Context,
	db *gorm.DB,
	onlineEventID string,
) []models.Order {
	var records []models.Order
	db.WithContext(ctx).Model(&models.Order{}).
		Where("online_event_id = ?", onlineEventID).
		Where("express_fee = ?", 0.00).
		Find(&records)
	return records
}

func (Order) SetReviewID(
	ctx context.Context,
	db *gorm.DB,
	orderID string,
	reviewID string,
) bool {
	rowsAffected := db.WithContext(ctx).Model(&models.Order{}).
		Where("id = ?", orderID).
		Where("review_id IS NULL OR review_id = ?", 0).
		Updates(&models.Order{
			ReviewID:    reviewID,                   // 关联评测记录
			OrderStatus: define.OrderStatusReviewed, // 更新订单状态为已评测
		}).
		RowsAffected
	return rowsAffected == 1
}

type StatusStatisticsT struct {
	OrderStatus int   `json:"order_status" gorm:"column:order_status"`
	Count       int64 `json:"count" gorm:"column:count"`
}

// StatusStatistics 状态统计
func (Order) StatusStatistics(
	ctx context.Context,
	db *gorm.DB,
	openid string,
) []StatusStatisticsT {
	var records []StatusStatisticsT
	// 待支付的订单
	// 未超过15分钟的普通订单+未超过一周的活动订单
	var unpaidOrder StatusStatisticsT
	db.WithContext(ctx).Model(&models.Order{}).
		Where("openid = ?", openid).
		Where("order_status = ?", 1).
		Where(
			db.Where("online_event_id > 0 AND created_at >= ?", time.Now().Unix()-3600*24*7).
				Or("online_event_id IS NULL AND created_at >= ?", time.Now().Unix()-15*60),
		).
		Group("order_status").
		Select("count(*) as count", "order_status").
		Take(&unpaidOrder)

	db.WithContext(ctx).Model(&models.Order{}).
		Where("openid = ?", openid).
		Where("order_status IN ?", []int{
			define.OrderStatusApplyingPending, // 待揭晓
			define.OrderStatusToPickUp,        // 待取货
			define.OrderStatusPendingReview,   // 待评论
		}).
		Group("order_status").
		Select("count(*) as count", "order_status").
		Find(&records)
	return append(records, unpaidOrder)
}

// UpdateOrderStatus 更新订单状态
func (Order) UpdateOrderStatus(
	ctx context.Context,
	db *gorm.DB,
	outTradeNo string,
	orderStatus int,
) error {
	return db.WithContext(ctx).Model(&models.Order{}).
		Where("batch_id = ?", outTradeNo).
		Update("order_status", orderStatus).Error
}
